﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections;
using System.IO;
using System.Security.Cryptography;
using System.Reflection;

namespace CheckSum
{
    class Program
    {
        public static ArrayList al = new ArrayList();//定义存储文件和文件夹名的数组
        public static int aaa = 0;//定义标志位参数，递归时判断该参数，若不为0则非第一次递归
        static void Main(string[] args)
        {
            string path = args[0];
            GetAllDirList(path);

            foreach (string str in al)
            {
                string md5 = MD5File(str);
                Console.WriteLine(str + " : " + md5);
                WriteLog(str, md5);
            }

        }
        public static void GetAllDirList(string strBaseDir)
        {
            DirectoryInfo di = new DirectoryInfo(strBaseDir);
            DirectoryInfo[] diA = di.GetDirectories();
            if (aaa == 0)
            {
                FileInfo[] fis2 = di.GetFiles();   //有关目录下的文件   
                for (int i2 = 0; i2 < fis2.Length; i2++)
                {
                    al.Add(fis2[i2].FullName);
                    //fis2[i2].FullName是根目录中文件的绝对地址，把它记录在ArrayList中
                }
            }
            for (int i = 0; i < diA.Length; i++)
            {
                aaa++;
                al.Add(diA[i].FullName + "\t<目录>");
                //diA[i].FullName是某个子目录的绝对地址，把它记录在ArrayList中
                DirectoryInfo di1 = new DirectoryInfo(diA[i].FullName);
                DirectoryInfo[] diA1 = di1.GetDirectories();
                FileInfo[] fis1 = di1.GetFiles();   //有关目录下的文件   
                for (int ii = 0; ii < fis1.Length; ii++)
                {
                    al.Add(fis1[ii].FullName);
                    //fis1[ii].FullName是某个子目录中文件的绝对地址，把它记录在ArrayList中

                }
                GetAllDirList(diA[i].FullName);
                //注意：递归了。逻辑思维正常的人应该能反应过来
            }
        }
        public static string MD5File(string fileName)
        {
            return HashFile(fileName, "md5");
        }

        /// <summary>
        /// 计算文件的哈希值
        /// </summary>
        /// <param name="fileName">要计算哈希值的文件名和路径</param>
        /// <param name="algName">算法:sha1,md5</param>
        /// <returns>哈希值16进制字符串</returns>
        public static string HashFile(string fileName, string algName)
        {
            if (!System.IO.File.Exists(fileName))
                return string.Empty;

            FileStream fs = new FileStream(fileName, FileMode.Open, FileAccess.Read);
            byte[] hashBytes = HashData(fs, algName);
            fs.Close();
            return ByteArrayToHexString(hashBytes);
        }

        /// <summary>
        /// 计算哈希值
        /// </summary>
        /// <param name="stream">要计算哈希值的 Stream</param>
        /// <param name="algName">算法:sha1,md5</param>
        /// <returns>哈希值字节数组</returns>
        public static byte[] HashData(Stream stream, string algName)
        {
            HashAlgorithm algorithm;
            if (algName == null)
            {
                throw new ArgumentNullException("algName 不能为 null");
            }
            if (string.Compare(algName, "sha1", true) == 0)
            {
                algorithm = SHA1.Create();
            }
            else
            {
                if (string.Compare(algName, "md5", true) != 0)
                {
                    throw new Exception("algName 只能使用 sha1 或 md5");
                }
                algorithm = MD5.Create();
            }
            return algorithm.ComputeHash(stream);
        }

        public static string ByteArrayToHexString(byte[] buf)
        {
            int iLen = 0;

            // 通过反射获取 MachineKeySection 中的 ByteArrayToHexString 方法，该方法用于将字节数组转换为16进制表示的字符串。
            Type type = typeof(System.Web.Configuration.MachineKeySection);
            MethodInfo byteArrayToHexString = type.GetMethod("ByteArrayToHexString", BindingFlags.Static | BindingFlags.NonPublic);

            // 字节数组转换为16进制表示的字符串
            return (string)byteArrayToHexString.Invoke(null, new object[] { buf, iLen });
        }

        public static void WriteLog(string readme, string readme2)
        {
            string log = @"AiOlog.txt";
            StreamWriter dout = new StreamWriter(log, true);
            dout.Write(readme + "\t" + readme2+"\r\n");
            //debug==================================================  
            dout.Close();
        }

    }
}
